package humynn.sbd
{
	import flash.display.*;
	import flash.display.Sprite;
	import flash.events.Event;
	import flash.events.MouseEvent;
	import flash.events.TimerEvent;
	import flash.geom.Point;
	import flash.geom.Rectangle;
	import flash.media.SoundChannel;
	import flash.text.Font;
	import flash.utils.Timer;
	
	import humynn.engine.Button;
	import humynn.engine.Entity;
	import humynn.engine.ImageManager;
	import humynn.engine.Input;
	import humynn.engine.Label;
	import humynn.engine.Renderer;
	import humynn.engine.Screen;
	import humynn.engine.ScreenManager;
	import humynn.engine.SoundManager;
	
	[SWF(width='800',height='600',backgroundColor='#ffffff',frameRate='60')]

	public class Main extends Sprite
	{
		private var _loadingScreen:Screen;
		private var _loadingLabel:Label;
		
		private var _imgLoaded:Boolean = false;
		private var _sndLoaded:Boolean = false;
		
		private var _superScreen:Screen;
		private var _soundButton:Button;
		
		private var _mainMenuScreen:Screen;
		private var _playButton:Button;
		private var _umeLogo:Entity;
		
		private var _diffScreen:Screen;
		private var _easyButton:Button;
		private var _medButton:Button;
		private var _hardButton:Button;
		
		private var _playingScreen:Screen;
		private var _bugMan:StinkBugManager;
		private var _health:HealthBar;
		private var _resetHealth:Boolean;
		private var _waveTimer:Timer;
		private var _timeBar:TimerBar;
		private var _wave:int;
		private var _bugDelay:Number;
		private var _healthLabel:Label;
		private var _timerLabel:Label;
		
		private var _waveEndScreen:Screen;
		private var _tipTitle:Label;
		private var _tipBody:Label;
		private var _nextWaveButton:Button;
		
		private var _gameOverScreen:Screen;
		private var _gameOverTimer:Timer;
		
		private var _screenMan:ScreenManager;
		private var _input:Input;
		private var _renderer:Renderer;
		
		private var _but:Button;
		private var _text:Label;
		
		private var _mainMenuMusic:SoundChannel;
		private var _gamePlayMusic:SoundChannel;
		
		private var _difficultyMod:Number;
		
		public function Main()
		{
			var bmpData:BitmapData = new BitmapData(stage.stageWidth, stage.stageHeight);
			var bmp:Bitmap = new Bitmap(bmpData);
			
			stage.addChild(bmp);
			
			_renderer = new Renderer(bmpData);
			_input = new Input(stage);
			_screenMan = new ScreenManager();
			
			Settings.load();
			Tips.loadTips();
			
			ImageManager.beginPreload();
			ImageManager.completed = imgCompleted;
			
			SoundManager.beginPreload();
			SoundManager.completed = sndCompleted;
			
			loadingScreen();
			
			this.addEventListener(Event.ENTER_FRAME, doFrame);
		}
		
		/**
		 * Called when the images are finished loading.
		 */
		private function imgCompleted():void
		{
			_imgLoaded = true;
			
			checkStartGame();
		}
		
		/**
		 * Called when the sounds are finished loading.
		 */
		private function sndCompleted():void
		{
			_sndLoaded = true;
			
			checkStartGame();
		}
		
		/**
		 * Checks to make sure that the sounds and the images are loaded
		 * and then starts the game if they are.
		 */
		private function checkStartGame():void
		{
			if(_imgLoaded && _sndLoaded)
			{
				startGame();
			}
		}
		
		/**
		 * Creates the loading screen. Very simple black text on a
		 * white background.
		 */
		private function loadingScreen():void
		{
			_loadingScreen = new Screen();
			
			_loadingLabel = new Label();
			_loadingLabel.color = 0xFFFFFFFF;
			_loadingLabel.text = "Loading...";
			_loadingLabel.x = (800 - _loadingLabel.width) / 2;
			_loadingLabel.y = (600 - _loadingLabel.height) / 2;
			_loadingScreen.addControl(_loadingLabel);
			
			_screenMan.addScreen(_loadingScreen);
		}
		
		/**
		 * Sets up the super screen and starts up the game.
		 */
		private function startGame():void
		{
			_superScreen = new Screen();
			
			_soundButton = new Button("sound.png", 800 - 32, 600 - 32);
			_soundButton.addEventListener(MouseEvent.CLICK, toggleSound);
			_superScreen.addControl(_soundButton);
			
			_screenMan.remScreen(_loadingScreen);
			showMainMenu(null);
		}
		
		/**
		 * Toggles sound on and off.
		 * 
		 * @param e Ignored.
		 */		
		private function toggleSound(e:Event):void
		{
			var vol:uint = 100 - SoundManager.getGlobalVolume();
			SoundManager.setGobalVolume(vol);
			
			var index:uint = 1 - _soundButton.animation;
			_soundButton.animation = index;
		}
		
		/**
		 * Sets up and shows the main menu.
		 * 
		 * @param e Ignored.
		 */
		private function showMainMenu(e:TimerEvent):void
		{
			_screenMan.clear();
			
			_mainMenuScreen = new Screen();
			_mainMenuScreen.background = "title.png";
			
			_playButton = new Button("playnow.png", 400, 450);
			_playButton.addEventListener(MouseEvent.CLICK, chooseDifficulty);
			_mainMenuScreen.addControl(_playButton);
			
			_umeLogo = new Entity();
			_umeLogo.imageFile = "umelogo.png";
			_umeLogo.x = 25;
			_umeLogo.y = 475;
			_mainMenuScreen.addEntity(_umeLogo);
			
			_mainMenuMusic = SoundManager.play("mainmenu.mp3", true);
			
			_screenMan.addScreen(_mainMenuScreen);
		}
		
		/**
		 * Shows the difficulty menu screen.
		 * 
		 * param e Ignored.
		 */
		private function chooseDifficulty(e:MouseEvent):void
		{
			_diffScreen = new Screen();
			_diffScreen.background = "title.png";
			
			_easyButton = new Button("easy.png", 400, 375);
			_easyButton.addEventListener(MouseEvent.CLICK, startEasy);
			_diffScreen.addControl(_easyButton);
			
			_medButton = new Button("med.png", 400, 450);
			_medButton.addEventListener(MouseEvent.CLICK, startMed);
			_diffScreen.addControl(_medButton);
			
			_hardButton = new Button("hard.png", 400, 525);
			_hardButton.addEventListener(MouseEvent.CLICK, startHard);
			_diffScreen.addControl(_hardButton);
			
			_diffScreen.addEntity(_umeLogo);
			
			_screenMan.remScreen(_mainMenuScreen);
			_screenMan.addScreen(_diffScreen);
		}
		
		/**
		 * Starts an easy mode game.
		 * 
		 * @param e Ignored.
		 */
		private function startEasy(e:Event):void
		{
			_bugDelay = Settings.bugInterval;
			
			_bugMan = new StinkBugManager();
			_bugMan.imageFile = "stinkbug.png";
			_bugMan.interval = _bugDelay * 1000;
			_bugMan.stateDelay = Settings.bugStateDelay;
			
			_resetHealth = true;
			
			_difficultyMod = 0.7;
			
			playGame();
		}
		
		/**
		 * Starts an easy mode game.
		 * 
		 * @param e Ignored.
		 */
		private function startMed(e:Event):void
		{
			_bugDelay = Settings.bugInterval;
			
			_bugMan = new StinkBugManager();
			_bugMan.imageFile = "stinkbug.png";
			_bugMan.interval = _bugDelay * 1000;
			_bugMan.stateDelay = Settings.bugStateDelay;
			
			_resetHealth = false;
			
			_difficultyMod = 0.85;
			
			playGame();
		}
		
		/**
		 * Starts an easy mode game.
		 * 
		 * @param e Ignored.
		 */
		private function startHard(e:Event):void
		{
			_bugDelay = Settings.bugInterval;
			
			_bugMan = new StinkBugManager();
			_bugMan.imageFile = "stinkbug.png";
			_bugMan.interval = _bugDelay * 1000;
			_bugMan.stateDelay = Settings.bugStateDelay / 2;
			
			_resetHealth = false;
			
			_difficultyMod = 1;
			
			playGame();
		}
		
		/**
		 * Called when the Play Now button is clicked. This creates the
		 * playing screen.
		 * 
		 * @param e Ignored.
		 */
		private function playGame():void
		{
			_mainMenuMusic.stop();
			Tips.randomize(Settings.rounds);
			
			_input.resetClicks();
			
			_playingScreen = new Screen();
			_playingScreen.background = "background.png";
			_playingScreen.blocksUpdate = true;
			
			_bugMan.start();
			_playingScreen.addEntity(_bugMan);
			
			_health = new HealthBar(_bugMan);
			_health.x = 25;
			_health.y = 25;
			_health.addEventListener(Event.COMPLETE, gameOver);
			_playingScreen.addControl(_health);
			
			_timeBar = new TimerBar();
			_timeBar.x = 673;
			_timeBar.y = 25;
			_playingScreen.addControl(_timeBar);
			
			_waveTimer = new Timer(100, Settings.roundLength * 10);
			_waveTimer.addEventListener(TimerEvent.TIMER, _timeBar.updateProgress);
			_waveTimer.addEventListener(TimerEvent.TIMER_COMPLETE, waveEnd);
			
			_healthLabel = new Label();
			_healthLabel.color = 0xFF000000;
			_healthLabel.fontSize = 15;
			_healthLabel.text = "Health";
			_healthLabel.x = _health.x + 50 - _healthLabel.width / 2;
			_healthLabel.y = _health.y + 14 - _healthLabel.height / 2;
			_playingScreen.addControl(_healthLabel);
			
			_timerLabel = new Label();
			_timerLabel.color = 0xFF000000;
			_timerLabel.fontSize = 15;
			_timerLabel.text = "Time Left";
			_timerLabel.x = _timeBar.x + 50 - _timerLabel.width / 2;
			_timerLabel.y = _timeBar.y + 14 - _timerLabel.height / 2;
			_playingScreen.addControl(_timerLabel);
			
			_wave = 1;
			
			_waveTimer.start();
			
			_gamePlayMusic = SoundManager.play("gameplay.mp3", true);
			
			_screenMan.remScreen(_diffScreen);
			_screenMan.addScreen(_playingScreen);
		}
		
		/**
		 * Called when a wave of stink bugs is over. Creates a new
		 * informational screen that shows the tips.
		 * 
		 * @param e Ignored.
		 */
		private function waveEnd(e:TimerEvent):void
		{
			if(_wave == Settings.rounds)
			{
				victory();
				return;
			}
			
			_waveEndScreen = new Screen();
			_waveEndScreen.background = "infoscreen.png";
			_waveEndScreen.blocksUpdate = true;
			_waveEndScreen.loc.x = 25;
			_waveEndScreen.loc.y = 25;
			
			_tipTitle = new Label(100, 50);
			_tipTitle.color = 0xFFFFFFFF;
			_tipTitle.fontSize = 50;
			_tipTitle.text = Tips.getTipTitle(_wave);
			_tipTitle.x = 400 - (_tipTitle.width / 2);
			_waveEndScreen.addControl(_tipTitle);
			
			_tipBody = new Label(100, 120);
			_tipBody.color = 0xFFFFFFFF;
			_tipBody.fontSize = 20;
			_tipBody.text = Tips.getTipBody(_wave);
			_tipBody.width = 600;
			_tipBody.wordWrap = true;
			_waveEndScreen.addControl(_tipBody);
			
			_nextWaveButton = new Button("next.png", 250, 475);
			_nextWaveButton.addEventListener(MouseEvent.CLICK, doneReading);
			_waveEndScreen.addControl(_nextWaveButton);
			
			_bugMan.stop();
			
			_screenMan.addScreen(_waveEndScreen);
		}
		
		/**
		 * Called when the user is finished reading the tip. This starts
		 * up the next wave of stink bugs.
		 * 
		 * @param e Ignored
		 */
		private function doneReading(e:MouseEvent):void
		{
			_bugDelay -= Settings.bugIntervalMod;
			
			_bugMan.reset();
			_bugMan.interval = _bugDelay * 1000;
			
			if(_resetHealth)
			{
				_health.reset();
			}
			
			_waveTimer.reset();
			_waveTimer.start();
			_wave++;
			
			_screenMan.remScreen(_waveEndScreen);
		}
		
		/**
		 * Called when the health bar reaches 0. Creates a game over
		 * screen and delays returning to the start menu.
		 * 
		 * @param e Ignored.
		 */
		private function gameOver(e:Event):void
		{
			_bugMan.flood();
			_waveTimer.stop();
			_gamePlayMusic.stop();
			
			_gameOverScreen = new Screen();
			_gameOverScreen.background = "gameover.png";
			_gameOverScreen.blocksUpdate = true;
			_gameOverScreen.loc.x = 200;
			_gameOverScreen.loc.y = 150;
			
			_gameOverTimer = new Timer(5000, 1);
			_gameOverTimer.addEventListener(TimerEvent.TIMER, showMainMenu);
			_gameOverTimer.start();
			
			SoundManager.play("gameover.mp3");
			
			_screenMan.addScreen(_gameOverScreen);
		}
		
		/**
		 * Called when the last wave is survived. Creates a victory
		 * screen and delays before showing the main menu.
		 */
		private function victory():void
		{
			_bugMan.stop();
			_waveTimer.stop();
			_gamePlayMusic.stop();
			
			_waveEndScreen = new Screen();
			_waveEndScreen.background = "infoscreen.png";
			_waveEndScreen.blocksUpdate = true;
			_waveEndScreen.loc.x = 25;
			_waveEndScreen.loc.y = 25;
			
			_tipTitle = new Label(100, 50);
			_tipTitle.color = 0xFFFFFFFF;
			_tipTitle.fontSize = 50;
			_tipTitle.text = "You Survived!";
			_tipTitle.x = 400 - (_tipTitle.width / 2);
			_waveEndScreen.addControl(_tipTitle);
			
			_tipBody = new Label(100, 120);
			_tipBody.color = 0xFFFFFFFF;
			_tipBody.fontSize = 20;
			_tipBody.text = getScoreString();
			_tipBody.width = 600;
			_tipBody.wordWrap = true;
			_waveEndScreen.addControl(_tipBody);
			
			_gameOverTimer = new Timer(12000, 1);
			_gameOverTimer.addEventListener(TimerEvent.TIMER, showMainMenu);
			_gameOverTimer.start();
			
			SoundManager.play("victory.mp3");
			
			_screenMan.addScreen(_waveEndScreen);
		}
		
		/**
		 * Returns a string containing the remaining health, the number of
		 * clicks and the total score.
		 */
		private function getScoreString():String
		{
			var scoreText:String;
			
			var health:int = _health.health;
			var clicks:int = _input.clicks;
			
			var score:int = ((100 * health) - (10 * clicks / Settings.rounds)) * _difficultyMod;
			
			scoreText = "You had " + health + "% health remaining and used " + clicks + " clicks to win the game.\n\nYour score: " + score;
			
			return scoreText;
		}
		
		/**
		 * The game loop.
		 * 
		 * @param e Ignored.
		 */
		private function doFrame(e:Event):void
		{
			if(_superScreen != null)
			{
				_superScreen.update(_input);
			}
			_screenMan.updateScene(_input);
			
			_renderer.beginDraw(0xFF000000);
			
			_screenMan.drawScene(_renderer);
			if(_superScreen != null)
			{
				_superScreen.draw(_renderer);
			}
			
			_renderer.endDraw();
		}
	}
}